/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/common.hpp>
#include <baja/math.hpp>

#include <baja/graphics/scenes/scenes_fwd.hpp>

namespace baja { namespace graphics { namespace scenes {

namespace m = baja::math;

// iscene_node represents a node in a scene graph. A scene node has a
// translation, rotation and scale associated with it. It also contains
// zero or more child scene nodes. 
interface iscene_node : public ibase
{
    BAJA_INTERFACE(iscene_node,"6F9EBB95-05CA-478e-98FF-9005AD031458")

    virtual void render(const std::shared_ptr<iengine>& graphics) = 0;

    virtual void setDefaultEffect(const standard_effect defaultEffect) = 0;

    virtual std::shared_ptr<ieffect2> getCustomEffect() = 0;
    virtual void setCustomEffect(const std::shared_ptr<ieffect2>& effect) = 0;

    virtual void updateTransforms(
        const m::matrix44& parentToWorld, 
        const m::matrix44& worldToParent, 
        bool forceUpdate
        ) = 0;

    virtual void getLocalToParent(m::matrix44* localToParent) = 0;
    virtual void getLocalToWorld(m::matrix44* localToWorld) = 0;
    virtual void getWorldToLocal(m::matrix44* worldToLocal) = 0;

    virtual void getLocalPosition(m::point3d* position) = 0;
    virtual void getWorldPosition(m::point3d* position) = 0;
    virtual void setPosition(const m::point3d& position) = 0;

    virtual void getScale(m::vector3d* scale) = 0;
    virtual void setScale(const m::vector3d& scale) = 0;
    virtual void setScaleUniform(const float32 scale) = 0;

    virtual void getRotation(m::matrix44* rotation) = 0;
    virtual void setRotation(const m::matrix44& rotation) = 0;
    
    virtual size_t getChildCount() = 0;
    virtual std::shared_ptr<iscene_node> getChild(size_t childIndex) = 0;

    virtual bool containsChild(const std::shared_ptr<iscene_node>& child) = 0;
    virtual void addChild(const std::shared_ptr<iscene_node>& child) = 0;
    virtual void removeChild(const std::shared_ptr<iscene_node>& child) = 0;
    virtual void removeChildAtIndex(const size_t childIndex) = 0;
    virtual void removeAllChildren() = 0;

    virtual std::shared_ptr<iscene_node> getParent() = 0;
    virtual void setParent(const std::shared_ptr<iscene_node>& parent) = 0; 

    virtual bool getIsVisible() = 0;
    virtual void setIsVisible(bool isVisible) = 0;

    virtual uint32 getRenderPriority() = 0;
    virtual void setRenderPriority(const int32 pri) = 0;

    virtual bool pixelHitTest(
        const std::shared_ptr<iscene_transformer>& sceneTransformer,
        const m::point2d& pixel,
        m::point3d* hitPositionLocalSpace) = 0;
};

// iprepared_scene contains the collection of scene nodes and their transformations
// into world space. The collection can be iterated over and rendered.
interface iprepared_scene : public ibase
{
    BAJA_INTERFACE(iprepared_scene, "31A49844-0F25-4e94-8C11-C755AF945DEC") 

    virtual std::shared_ptr<iscene_transformer> getSceneTransformer() = 0;

    virtual size_t getNodeCount() = 0;
    virtual std::shared_ptr<iscene_node> getNode(const size_t index) = 0; 

    virtual void render(const std::shared_ptr<iengine>& graphics) = 0;
};

// iscene_graph represents a scene graph which can be rendered to the graphics engine.
// This interface prepares the scene for rendering, and also provides simple pixel
// to scene node hit testing logic.
interface iscene_graph : public iscene_node
{
    BAJA_INTERFACE(iscene_graph,"9FCBE928-DC3D-4a0b-8BC4-DC9CE9682F3B") 

    virtual std::shared_ptr<iprepared_scene> prepareForRendering(const std::shared_ptr<iengine>& graphics) = 0;
};

// ibillboard_node represents a billboarded image. The billboard
// can be colored and textured.
interface ibillboard_node : public iscene_node
{
    BAJA_INTERFACE(ibillboard_node, "4D02402F-2DEA-4758-AA27-95D0DD401200") 

    virtual std::shared_ptr<itexture> getTexture() = 0;
    virtual std::shared_ptr<itexture> getTextureAtIndex(uint32 index) = 0;

    virtual void setTexture(const std::shared_ptr<itexture>& texture) = 0;
    virtual void setTextureAtIndex(uint32 index, const std::shared_ptr<itexture>& texture) = 0;

    virtual void getSize(float32* width, float32* height) = 0;
    virtual void setSize(const std::shared_ptr<iengine>& graphics, const float32 width, const float32 height) = 0;

    virtual std::shared_ptr<imaterial> getMaterial() = 0;
    virtual std::shared_ptr<imaterial_collection> getMaterialCollection() = 0;
};

// imesh_node represents a mesh object in the scene.
interface imesh_node : public iscene_node
{
    BAJA_INTERFACE(imesh_node, "554293F9-C12A-4f09-8C2B-DABF0525F32E")

    virtual std::shared_ptr<imesh> getMesh() = 0;
    virtual void setMesh(const std::shared_ptr<imesh>& mesh) = 0;

    virtual std::shared_ptr<imaterial_collection> getMaterialCollection() = 0;
};

}}} // namespace baja.graphics.scenes
